import launch 
import launch_ros
from ament_index_python.packages import get_package_share_directory#获取功能包的共享目录路径
import os#处理文件路径
import launch_ros.parameter_descriptions
from launch.launch_description_sources import PythonLaunchDescriptionSource#动态加载其它的launch文件
def generate_launch_description():
    urdf_package_path=get_package_share_directory("fishbot_description")#获取功能包的share路径
    default_xacro_path=os.path.join(urdf_package_path,"urdf","fishbot/fishbot.urdf.xacro")#拼接 URDF/Xacro 模型文件路径（fishbot.urdf.xacro
    default_gazebo_world_path=os.path.join(urdf_package_path,"world","my_room.sdf")#拼接 Gazebo 世界文件路径（custom_room.world)
    #声明一个urdf目录的参数,方便修改

    action_declare_arg_mode_path=launch.actions.DeclareLaunchArgument(
        name="model",default_value=str(default_xacro_path),description="加载的模型文件路径"
    )
    """
    定义一个名为 model 的 Launch 参数，默认值为 default_xacro_path,也就是我们的机器人仿真的路径
    允许用户在启动时通过命令行覆盖模型路径
    """
    #通过文件路径获取内容并且转换成参数值对象,以供传入robot_state_publisher
    substitutions_command_result=launch.substitutions.Command(["xacro ",launch.
    substitutions.LaunchConfiguration("model")])
    """
    调用 xacro 命令解析 URDF/Xacro 文件（通过 LaunchConfiguration 动态获取路径
    """

    robot_description_value=launch_ros.parameter_descriptions.ParameterValue(
        substitutions_command_result,value_type=str)
    """
    将解析结果转换为 ParameterValue 对象，供后续节点使用
    """

    action_robot_state_publisher=launch_ros.actions.Node(
        package="robot_state_publisher",
        executable="robot_state_publisher",
        parameters=[{"robot_description":robot_description_value}]
    )
    """
    启动 robot_state_publisher 节点，发布机器人的关节状态和 TF 变换。传入解析后的 URDF 模型（robot_description_value）
    """

    action_launch_gazebo = launch.actions.IncludeLaunchDescription(
        launch.launch_description_sources.PythonLaunchDescriptionSource(
            [get_package_share_directory('gazebo_ros'), '/launch', '/gazebo.launch.py']
        ),
        launch_arguments=[
            ('world', default_gazebo_world_path),
            ('verbose', 'true')
        ]
    )
    """
    action_spawn_entity = launch_ros.actions.Node(
    package='gazebo_ros',
    executable='spawn_entity.py',
    arguments=['-topic', '/robot_description', '-entity', 'fishbot', '-x', '1.0', '-y', '2.0', '-z', '0.5', '-Y', '1.57'],
    output='screen'

    """
    """
    动态加载 Gazebo 的官方 Launch 文件（gazebo.launch.py）。
    传递参数：
    world：指定自定义世界文件路径。
    verbose：启用详细日志输出
    """   
    action_spawn_entity = launch_ros.actions.Node(
        package='gazebo_ros',
        executable='spawn_entity.py',
        arguments=['-topic', '/robot_description', '-entity', 'fishbot']
    )
    """
    调用 spawn_entity.py 节点，将机器人模型加载到 Gazebo。
    参数说明：
        -topic /robot_description：从该话题获取机器人 URDF 描述。
        -entity fishbot：在 Gazebo 中命名为 fishbot 的实体
    """
    action_load_joint_state_controller=launch.actions.ExecuteProcess(
    cmd="ros2 control load_controller fishbot_joint_state_broadcaster --set-state active".split(' '),
    output="screen"
    )
    action_load_effort_controller=launch.actions.ExecuteProcess(
        cmd="ros2 control load_controller fishbot_effort_controller --set-state active".split(' '),
        output="screen"
    )
    return launch.LaunchDescription([
        action_declare_arg_mode_path,
        action_robot_state_publisher,
        action_launch_gazebo,
        action_spawn_entity,
        launch.actions.RegisterEventHandler(
            event_handler=launch.event_handlers.OnProcessExit(
                target_action=action_spawn_entity,
                on_exit=[action_load_joint_state_controller],
            )
        ),
        launch.actions.RegisterEventHandler(
            event_handler=launch.event_handlers.OnProcessExit(
                target_action=action_load_joint_state_controller,
                on_exit=[action_load_effort_controller],
            )
        )
    ])#然后的话,由于节点启动的部分是这个样子的,我们应该在action_spawn_entity执行完成之后再启动我们的加载控制器节点
